package urlqueue

import (
	"sync"

	"gitee.com/sillyman/gocommon/containers/queue"
)

// queueInMemory 一个URL列队，url存储内存中，，如果爬虫中途退出，需要重头开始爬
type queueInMemory struct {
	// q 一个fifo列队，存放 *url.URL
	fifoQueue *queue.Queue

	// hMap 保证加入列队的 URL 不重复
	hMap map[string]bool

	mu sync.Mutex
}

// New 创建一个内存列队实例
func NewQueueInMemory() URLQueue {
	return &queueInMemory{
		fifoQueue: queue.NewQueue(),
		hMap:      make(map[string]bool),
	}
}

// Push
func (q *queueInMemory) Push(rawurl, refererUrl string) error {
	myURL, err := ParseMyURL(rawurl, refererUrl)
	if err != nil {
		return nil
	}

	q.mu.Lock()
	defer q.mu.Unlock()

	if _, has := q.hMap[myURL.String()]; has {
		return nil
	}
	q.hMap[myURL.String()] = true
	q.fifoQueue.Push(myURL)
	return nil
}

// ForcePush
func (q *queueInMemory) ForcePush(myURL *MyURL) error {
	if myURL == nil {
		return nil
	}

	q.mu.Lock()
	defer q.mu.Unlock()

	q.hMap[myURL.String()] = true
	q.fifoQueue.Push(myURL)
	return nil
}

// Pop
func (q *queueInMemory) Pop() (*MyURL, error) {
	v, ok := q.fifoQueue.Pop()
	if ok {
		return v.(*MyURL), nil
	}
	return nil, nil
}

// GetQueueLen
func (q *queueInMemory) GetQueueLen() (int64, error) { return int64(q.fifoQueue.Len()), nil }

// GetTotalNumber
func (q *queueInMemory) GetTotalNumber() (int64, error) { return int64(len(q.hMap)), nil }
